﻿using Org.BouncyCastle.Asn1;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace SealManagement.Models
{
    public class GMSealInfo
    {
        public string SealId { get; set; }
        /// <summary>
        /// 印章名称
        /// </summary>
        public string SealName { get; set; }
        /// <summary>
        /// 印章类型  1单位印章 2个人印章
        /// </summary>
        public int SealType { get; set; }
        /// <summary>
        /// 制章时间
        /// </summary>
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 生效开始时间
        /// </summary>
        public DateTime StartTime { get; set; }
        /// <summary>
        /// 生效结束时间
        /// </summary>
        public DateTime EndTime { get; set; }
        /// <summary>
        /// 制章人证书序列号
        /// </summary>
        public string MakerCertSN { get; set; }
        /// <summary>
        /// 制章人证书Base64
        /// </summary>
        public byte[] MakerCertBytes { get; set; }
        /// <summary>
        /// 用户证书序列号
        /// </summary>
        public string UserCertSN { get; set; }
        /// <summary>
        /// 用户证书Base64
        /// </summary>
        public byte[] UserCertBytes { get; set; }
        /// <summary>
        /// 图片数据
        /// </summary>
        public byte[] ImageBytes { get; set; }

        public static GMSealInfo DecodeGMSeal(byte[] sealBytes)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream(sealBytes))
                {
                    GMSealInfo gmSealInfo = new GMSealInfo();
                    Asn1InputStream asn1InputStream = new Asn1InputStream(ms);
                    var asn1Seal = asn1InputStream.ReadObject();
                    if (asn1Seal is Asn1Sequence asn1SealSequence)
                    {
                        if (asn1SealSequence[0] is Asn1Sequence asn1SealInfo)
                        {
                            var headerInfo = asn1SealInfo[0];
                            var stampId = asn1SealInfo[1];
                            if (stampId is DerIA5String c)
                            {
                                gmSealInfo.SealId = c.GetString();
                            }
                            var stampInfo = asn1SealInfo[2];
                            var stampImage = asn1SealInfo[3];
                            if (stampInfo is Asn1Sequence stampInfoSequence)
                            {
                                if (stampInfoSequence[0] is DerInteger sealTypeInterger)
                                {
                                    gmSealInfo.SealType = sealTypeInterger.Value.IntValue;
                                }

                                if (stampInfoSequence[1] is DerUtf8String sealNameUtf8String)
                                {
                                    gmSealInfo.SealName = sealNameUtf8String.GetString();
                                }

                                Asn1Sequence certList = null;
                                Asn1Object derCreateTime = null;
                                Asn1Object derStartTime = null;
                                Asn1Object derEndTime = null;


                                if (stampInfoSequence[2] is DerInteger certType)
                                {
                                    certList = stampInfoSequence[3] as Asn1Sequence;
                                    derCreateTime = stampInfoSequence[4] as DerGeneralizedTime;
                                    derStartTime = stampInfoSequence[5] as DerGeneralizedTime;
                                    derEndTime = stampInfoSequence[6] as DerGeneralizedTime;
                                }
                                else
                                {
                                    certList = stampInfoSequence[2] as Asn1Sequence;
                                    derCreateTime = stampInfoSequence[3] as DerUtcTime;
                                    derStartTime = stampInfoSequence[4] as DerUtcTime;
                                    derEndTime = stampInfoSequence[5] as DerUtcTime;
                                }
                                if (certList?[0] is Asn1OctetString userCertOctetString)
                                {
                                    gmSealInfo.UserCertBytes = userCertOctetString.GetOctets();
                                    gmSealInfo.UserCertSN = new X509Certificate2(gmSealInfo.UserCertBytes).SerialNumber;
                                }
                                else if (certList?[0] is Asn1Sequence userCertSequence)
                                {
                                    gmSealInfo.UserCertBytes = userCertSequence.GetDerEncoded();
                                    gmSealInfo.UserCertSN = new X509Certificate2(gmSealInfo.UserCertBytes).SerialNumber;
                                }

                                gmSealInfo.CreateTime = (derCreateTime is DerUtcTime)
                                    ? (derCreateTime as DerUtcTime).ToDateTime()
                                    : (derCreateTime as DerGeneralizedTime)?.ToDateTime() ?? DateTime.MinValue;
                                gmSealInfo.StartTime = (derStartTime is DerUtcTime)
                                    ? (derStartTime as DerUtcTime).ToDateTime()
                                    : (derStartTime as DerGeneralizedTime)?.ToDateTime() ?? DateTime.MinValue;
                                gmSealInfo.EndTime = (derEndTime is DerUtcTime)
                                    ? (derEndTime as DerUtcTime).ToDateTime()
                                    : (derEndTime as DerGeneralizedTime)?.ToDateTime() ?? DateTime.MinValue;

                            }

                            if (stampImage is Asn1Sequence i && i[1] is Asn1OctetString imageOctetString)
                            {
                                gmSealInfo.ImageBytes = imageOctetString.GetOctets();
                            }
                        }

                        Asn1OctetString makerCertAsn1OctetString = null;
                        if (asn1SealSequence[1] is Asn1Sequence asn1SigInfo && (makerCertAsn1OctetString = asn1SigInfo[0] as Asn1OctetString) != null)
                        {
                            gmSealInfo.MakerCertBytes = makerCertAsn1OctetString.GetOctets();
                            gmSealInfo.MakerCertSN = new X509Certificate2(gmSealInfo.MakerCertBytes).SerialNumber;
                        }
                        else if ((makerCertAsn1OctetString = asn1SealSequence[1] as Asn1OctetString) != null)
                        {
                            gmSealInfo.MakerCertBytes = makerCertAsn1OctetString.GetOctets();
                            gmSealInfo.MakerCertSN = new X509Certificate2(gmSealInfo.MakerCertBytes).SerialNumber;
                        }
                        else
                        {
                            return null;
                        }

                        return gmSealInfo;
                    }
                }
            }
            catch (Exception e)
            {
                return null;
            }
            return null;
        }
    }
}
